package com.github.binarywang.demo.wx.mp.controller;


import com.github.binarywang.demo.wx.mp.config.CommonConstant;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;

/**
 * https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
 */
@RequestMapping("/auth/{appId}")
@RestController
@Slf4j
public class AuthController {

    @Autowired
    private WxMpService wxMpService;

    /**
     * 获取授权登陆的URL
     * https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
     *
     * <pre>
     * 1/需要一个已经认证的微信公众号:https://developers.weixin.qq.com/community/develop/doc/00006edfc4c9b093793e7eb1c5d000
     * 2/配置“网页授权域名”和"业务域名"
     * 3/调用此接口,生成授权登录url
     * </pre>
     *
     * note:访问生成的url时,
     *  1/如果已经关注过公众号,则授权之后,一段时间内不会再次弹出申请授权的窗口.
     *  2/如果客户未关注公众号,并不会让客户去关注公众号,只是在下面会提示:
     *  该网页需获取个人信息才可使用完整服务,当前仅可浏览部分内容.      使用完整服务 >
     *  当点击[使用完整服务]时,会弹出:
     *  xxx 申请 获取你的昵称、头像
     *
     * todo:授权后访问业务url时,微信服务器不会回调开发者接口,业务页面url无法感知openId,那么接口如何知道当前是哪个用户在参加活动???
     *
     *
     *  GET http://localhost:8080/auth/wxa4f880b9a8ed4e2c/url?url=http://zd4n4z.natappfree.cc/test/hello?name=anxiaole&state=250
     *
     * @param url
     * @param state 这是微信授权url后带的参数,非必填	重定向后会带上 state 参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
     * @return
     */
    @RequestMapping(value = "/url", method = RequestMethod.GET)
    public Object getAuthUrl(@PathVariable String appId, String url, String state) {
        return wxMpService.switchoverTo(appId).getOAuth2Service().buildAuthorizationUrl(url, CommonConstant.AUTH_USERINFO, state);
    }


    /**
     * 根据code获取access_token
     *
     * @param code
     * @return
     */
    @RequestMapping("/access_token")
    public Object getAccessToken(@PathVariable String appId, @RequestParam(value = "code") String code) {
        try {
            WxOAuth2AccessToken accessToken = wxMpService.switchoverTo(appId).getOAuth2Service().getAccessToken(code);
            System.out.println(accessToken.getAccessToken());
            // 由于access_token拥有较短的有效期，当access_token超时后，可以使用refresh_token进行刷新，refresh_token有效期为30天，当refresh_token失效之后，需要用户重新授权。
            System.out.println(accessToken.getRefreshToken());
            System.out.println(accessToken.getOpenId());
            return accessToken;
        } catch (WxErrorException e) {
            log.error("error", e);
            return e.toString();
        }
    }

    /**
     * 根据code获取用户信息
     *
     * @param code
     * @param lang
     * @return
     */
    @RequestMapping("/user_info")
    public Object getUserInfo(@PathVariable String appId, @RequestParam(value = "code") String code, String lang) {
        try {
            WxOAuth2UserInfo userInfo = wxMpService.switchoverTo(appId).getOAuth2Service().getUserInfo(wxMpService.getOAuth2Service().getAccessToken(code), lang);
            userInfo.getOpenid();
            userInfo.getNickname();
            userInfo.getHeadImgUrl();
            return userInfo;
        } catch (WxErrorException e) {
            log.error("error", e);
            return e.toString();
        }
    }

    /**
     * 刷新access_token
     *
     * @param refreshToken
     * @return
     */
    @RequestMapping("/refresh_token")
    public Object refreshToken(@PathVariable String appId, @RequestParam(value = "refreshToken") String refreshToken) {
        try {
            return wxMpService.switchoverTo(appId).getOAuth2Service().refreshAccessToken(refreshToken);
        } catch (WxErrorException e) {
            log.error("error", e);
            return e.toString();
        }
    }
}
